package cn.iocoder.yudao.module.erp.service.finance.bankstatement;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.erp.controller.admin.finance.bankstatement.vo.BankStatementPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.finance.bankstatement.vo.BankStatementSaveReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.finance.bankstatementitem.vo.BankStatementItemPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.finance.bankstatement.BankStatementDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.finance.bankstatementitem.BankStatementItemDO;
import cn.iocoder.yudao.module.erp.dal.mysql.finance.bankstatement.BankStatementMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.finance.bankstatementitem.BankStatementItemMapper;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;

/**
 * 银行流水 Service 实现类
 * @author 天使管理员
 */
@Service
@Validated
public class BankStatementServiceImpl implements BankStatementService {

    @Resource
    private BankStatementMapper bankStatementMapper;
    @Resource
    private BankStatementItemMapper bankStatementItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createBankStatement(BankStatementSaveReqVO createReqVO) {
        Long count = bankStatementMapper.selectCountById(createReqVO.getId());
        if (count > 0) {
            throw exception(BANK_CARD_ID_EXISTS);
        }
        // 插入
        BankStatementDO bankStatement = BeanUtils.toBean(createReqVO, BankStatementDO.class);
        bankStatement.setDailyBalance(bankStatement.getInitAmount());
        bankStatementMapper.insert(bankStatement);
        // 插入子表
        BankStatementItemDO bankStatementItemDO = new BankStatementItemDO();
        bankStatementItemDO.setCardId(createReqVO.getId());
        bankStatementItemDO.setBalance(createReqVO.getInitAmount());
        bankStatementItemDO.setNote("卡初始余额");
        bankStatementItemMapper.insert(bankStatementItemDO);
//        createBankStatementItem(bankStatement.getId(), createReqVO.getBankStatementItems());
        // 返回
        return bankStatement.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBankStatement(BankStatementSaveReqVO updateReqVO) {
        // 校验存在
        validateBankStatementExists(updateReqVO.getId());
        // 更新
        BankStatementDO updateObj = BeanUtils.toBean(updateReqVO, BankStatementDO.class);
        bankStatementMapper.updateById(updateObj);

        // 更新子表
        updateBankStatementItemList(updateReqVO.getId(), updateReqVO.getBankStatementItems());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBankStatement(String id) {
        // 校验存在
        validateBankStatementExists(id);
        // 删除
        bankStatementMapper.deleteById(id);

        // 删除子表
        deleteBankStatementItemByCardId(id);
    }

    private void validateBankStatementExists(String id) {
        if (bankStatementMapper.selectById(id) == null) {
            throw exception(BANK_STATEMENT_NOT_EXISTS);
        }
    }

    @Override
    public BankStatementDO getBankStatement(String id) {
        return bankStatementMapper.selectById(id);
    }

    @Override
    public PageResult<BankStatementDO> getBankStatementPage(BankStatementPageReqVO pageReqVO) {
        return bankStatementMapper.selectPage(pageReqVO);
    }

//    @Override
//    public PageResult<BankStatementDO> getBankStatementPage(BankStatementPageReqVO reqVO) {
//        Integer pageNo = reqVO.getPageNo();
//        Integer pageSize = reqVO.getPageSize();
//        // 计算起始行
//        int offset = (pageNo - 1) * pageSize;
//        // 执行查询
//        List<BankStatementDO> list = bankStatementMapper.selectBankStatementPage(reqVO.getId(),reqVO.getCurrencyType(),offset,pageSize);
//        // 查询总数
//        Long totalCount = bankStatementMapper.selectCountById(reqVO.getId());
//        // 创建并返回分页结果，包含列表和总记录数
//        return new PageResult<>(list, totalCount);
//    }



    @Override
    public BankStatementDO getBankAmountTotal(BankStatementPageReqVO reqVO) {
//        Integer pageNo = reqVO.getPageNo();
//        Integer pageSize = reqVO.getPageSize();
//        // 计算起始行
//        int offset = (pageNo - 1) * pageSize;
//        // 执行查询
//        List<BankStatementDO> list = bankStatementMapper.selectBankStatementPage(reqVO.getId(),offset,pageSize);
        String cardId = reqVO.getCardId();
        BankStatementDO bankStatementDO = new BankStatementDO();
        if (cardId != null && !"".equals(cardId)) {
            return bankStatementMapper.selectBankStatementItem(cardId);
        }
        List<BankStatementDO> list = bankStatementMapper.selectBankStatement(reqVO.getId(), cardId, reqVO.getCurrencyType());
        //计算人民币
        BankStatementDO bankStatementRmbDO = sumMoneyByList(list, 1);
        bankStatementDO.setDayPaymentRmbSum(bankStatementRmbDO.getDayPaymentSum());
        bankStatementDO.setDailyExpensesRmbSum(bankStatementRmbDO.getDailyExpensesSum());
        bankStatementDO.setDailyBalanceRmbSum(bankStatementRmbDO.getDailyBalanceSum());

        //计算美元
        BankStatementDO bankStatementDollarDO = sumMoneyByList(list, 2);
        bankStatementDO.setDayPaymentDollarSum(bankStatementDollarDO.getDayPaymentSum());
        bankStatementDO.setDailyExpensesDollarSum(bankStatementDollarDO.getDailyExpensesSum());
        bankStatementDO.setDailyBalanceDollarSum(bankStatementDollarDO.getDailyBalanceSum());

        //计算人坚戈
        BankStatementDO bankStatementTengeDO = sumMoneyByList(list, 3);
        bankStatementDO.setDayPaymentTengeSum(bankStatementTengeDO.getDayPaymentSum());
        bankStatementDO.setDailyExpensesTengeSum(bankStatementTengeDO.getDailyExpensesSum());
        bankStatementDO.setDailyBalanceTengeSum(bankStatementTengeDO.getDailyBalanceSum());

        //计算卢布
        BankStatementDO bankStatementRubleDO = sumMoneyByList(list, 4);
        bankStatementDO.setDayPaymentRubleSum(bankStatementRubleDO.getDayPaymentSum());
        bankStatementDO.setDailyExpensesRubleSum(bankStatementRubleDO.getDailyExpensesSum());
        bankStatementDO.setDailyBalanceRubleSum(bankStatementRubleDO.getDailyBalanceSum());
        return bankStatementDO;
    }

    private BankStatementDO sumMoneyByList(List<BankStatementDO> list, Integer currencyType) {
        list = list.stream()
                .filter(bankStatement -> bankStatement.getCurrencyType() == currencyType)
                .collect(Collectors.toList());
        // 计算字段总和
        Double dayPaymentSum = list.stream()
                .mapToDouble(BankStatementDO::getDayPayment).sum();
        Double dailyExpensesSum = list.stream()
                .mapToDouble(BankStatementDO::getDailyExpenses).sum();
        Double dailyBalanceSum = list.stream()
                .mapToDouble(BankStatementDO::getDailyBalance).sum();
        BankStatementDO bankStatementDO = new BankStatementDO();
        bankStatementDO.setDayPaymentSum(dayPaymentSum);
        bankStatementDO.setDailyExpensesSum(dailyExpensesSum);
        bankStatementDO.setDailyBalanceSum(dailyBalanceSum);
        return bankStatementDO;
    }

    // ==================== 子表（银行流水明细） ====================

    @Override
    public PageResult<BankStatementItemDO> getBankStatementItemListByCardId(BankStatementItemPageReqVO pageReqVO) {
        return bankStatementItemMapper.selectListByCardId(pageReqVO);
    }

    private void createBankStatementItemList(String cardId, List<BankStatementItemDO> list) {
        if (list == null || list.size() == 0){
            return;
        }
        list.forEach(o -> o.setCardId(cardId));
        bankStatementItemMapper.insertBatch(list);
    }

    private void updateBankStatementItemList(String cardId, List<BankStatementItemDO> list) {
        if (list == null || list.size() == 0){
            return;
        }
        deleteBankStatementItemByCardId(cardId);
        list.forEach(o -> o.setCardId(cardId));
        createBankStatementItemList(cardId, list);
    }

    private void deleteBankStatementItemByCardId(String cardId) {
        bankStatementItemMapper.deleteByCardId(cardId);
    }
}